// 日志器、日志器管理、日志器建造者、局部和全局的建造者派生类
// 同步日志器：线程自己对消息进行输出
// 异步日志器：将日志消息放入缓冲区，由对应的异步线程对消息进行输出操作

#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__

#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <stdarg.h>
#include <atomic>
#include <mutex>
#include <unordered_map>

namespace snowdragon
{
    // enum class LoggerType
    // {
    //     SYNC_LOGGER = 0,
    //     ASYNC_LOGGER
    // };

    // 日志器基类，同步和异步属于派生类，继承于它
    class Logger
    {
    public:
        // 可放于类内
        enum class LoggerType // 日志器类型
        {
            SYNC_LOGGER = 0, // 同步日志器
            ASYNC_LOGGER     // 异步日志器
        };

        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, Formatter::ptr formatter, std::vector<Sink::ptr> &sinks, LogLevel::Level level = LogLevel::Level::DEBUG)
            : _logger_name(logger_name), _formatter(formatter), _sinks(sinks.begin(), sinks.end()), _level(level)
        {}

        // 修改异步日志器的安全类型
        virtual void modifyAsyncLoggerAndLooperSafeType(AsyncLooperSafeType safe_type) // 专门为AsyncLogger准备
        {}              // 加上{}，否则因为调用会报错。使用时是多态，基类没有，编译时会报错

        const std::string &getLoggerName()      // 获取日志器名
        {
            return _logger_name;
        }

        // 可添加
        LogLevel::Level getLoggerLevel()        // 获取日志等级
        {
            return _level;
        }

        // 对对应级别的日志进行输出，最后这些消息后输出到落地方式中
        void debug(const char *file, size_t line, const char *format...)        // 输出debug（调式）日志
        {
            if (!judgeLevel(LogLevel::Level::DEBUG))
                return;
            va_list vl;
            va_start(vl, format);
            log(file, line, LogLevel::Level::DEBUG, vl, format);
            va_end(vl);
        }
        void info(const char *file, size_t line, const char *format...)
        {
            if (!judgeLevel(LogLevel::Level::INFO))
                return;
            va_list vl;
            va_start(vl, format);
            log(file, line, LogLevel::Level::INFO, vl, format);
            va_end(vl);
        }
        void warn(const char *file, size_t line, const char *format...)
        {
            if (!judgeLevel(LogLevel::Level::WARN))
                return;
            va_list vl;
            va_start(vl, format);
            log(file, line, LogLevel::Level::WARN, vl, format);
            va_end(vl);
        }
        void error(const char *file, size_t line, const char *format...)
        {
            if (!judgeLevel(LogLevel::Level::ERROR))
                return;
            va_list vl;
            va_start(vl, format);
            log(file, line, LogLevel::Level::ERROR, vl, format);
            va_end(vl);
        }
        void fatal(const char *file, size_t line, const char *format...)
        {
            if (!judgeLevel(LogLevel::Level::FATAL))
                return;
            va_list vl;
            va_start(vl, format);
            log(file, line, LogLevel::Level::FATAL, vl, format);
            va_end(vl);
        }
        // 不需要公开
        // virtual void logIt(const std::string& message) = 0;
    protected:
        // 对各落地方式，将数据输出到其中
        virtual void logIt(const std::string &message) = 0;

    private:
        bool judgeLevel(LogLevel::Level level)          // 判断输出级别是否足够，即输出的日志级别需要大于或等于_level
        {
            return level >= _level;
        }
        // void log(const char* file, size_t line, Level level, const char* payload)
        // {
        //     Message mse(file, line, level, payload, _logger_name);
        // }
        // 获取不定参数的数据，进而构造Message对象，再将其传递给落地函数logIt
        void log(const char *file, size_t line, LogLevel::Level level, va_list vl, const char *format...)
        {
            char *buff;
            int len = vasprintf(&buff, format, vl);         // 获取不定参数中的数据
            if (len < 0)
            {
                std::cerr << "Logger log vasprintf error" << std::endl;
                return;
            }
            Message mse(file, line, level, buff, _logger_name);
            free(buff);                         // 释放资源
            logIt(_formatter->format(mse));         // 转换完再传递进去，即传递过去的mse数据是经过格式化后的了，可以直接落地，即输出
        }

    protected:
        std::string _logger_name;               // 日志器名
        Formatter::ptr _formatter;              // 格式化
        std::vector<Sink::ptr> _sinks;          // 落地方式集合
        std::atomic<LogLevel::Level> _level;    // 日志级别
        // LoggerType _logger_type;     // 被继承，不需要
        std::mutex _mutex;                      // 互斥锁，为了安全
    };

    // 建造者基类，负责建造日志器，即Logger对象
    class Builder
    {
    public:
        // Builder() = default;
        void buildLoggerName(const std::string &logger_name) { _logger_name = logger_name; }
        void buildLoggerType(Logger::LoggerType logger_type) { _logger_type = logger_type; }
        void buildLoggerLevel(LogLevel::Level level) { _level = level; }
        void buildLoggerFormatter(const std::string pattern = "[%d{%H:%M:%S}][%t][%c][%p][%f:%l]%T%m%n") { _formatter = std::make_shared<Formatter>(pattern); }
        // 可加const修饰和用引用
        void buildLoggerFormatter(const Formatter::ptr &formatter) { _formatter = formatter; }
        // 在AsyncLogger中设置更好
        // void buildAsyncLoggerLooperSafeType(AsyncLooperSafeType safe_type)    {   _safe_type = safe_type; }
        template <typename sinkType, typename... Args>
        void buildLoggerSink(Args &&...args)
        {
            _sinks.push_back(SinkFactory::createSink<sinkType>(std::forward<Args>(args)...)); // 记得加forward
        }
        virtual Logger::ptr build() = 0;            // 生成日志器

    protected:
        std::string _logger_name;               // 日志器名
        Formatter::ptr _formatter;              // 格式化
        std::vector<Sink::ptr> _sinks;          // 落地方式集合
        LogLevel::Level _level = LogLevel::Level::DEBUG;        // 日志级别
        Logger::LoggerType _logger_type = Logger::LoggerType::SYNC_LOGGER;      // 日志类型
        // 不需要用到
        // Logger::ptr _logger;
        // AsyncLooperSafeType _safe_type = AsyncLooperSafeType::SAFE_ASYNC_LOOPER;
    };

    // 同步日志器
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name, Formatter::ptr formatter, std::vector<Sink::ptr> &sinks, LogLevel::Level level = LogLevel::Level::DEBUG)
            : Logger(logger_name, formatter, sinks, level)
        {}
        // 对基类中，将数据输出的落地集合中的各落地方式的重写
        void logIt(const std::string &message)
        {
            // 加锁，线程安全
            std::unique_lock<std::mutex> ul(_mutex);
            // 可加，但没多大用处，因为Builder派生类中会判空，如果为空会加一个
            if (_sinks.empty())
            {
                return;
            }
            for (auto &sink : _sinks)
            {
                sink->log(message.c_str(), message.size());
            }
        }
        // 可加，可不加。这函数主要是针对异步日志器的
        void modifyAsyncLoggerAndLooperSafeType(AsyncLooperSafeType safe_type)
        {}
    };

    // 异步日志器
    class AsyncLogger : public Logger // 写在LocalLoggerBuilder前，不用在LocalLoggerBuilder前声明而导致继承未知
    {
    public:
        AsyncLogger(const std::string &logger_name, Formatter::ptr formatter,
                    std::vector<Sink::ptr> &sinks, LogLevel::Level level = LogLevel::Level::DEBUG,
                    AsyncLooperSafeType safe_type = AsyncLooperSafeType::SAFE_ASYNC_LOOPER)
            : Logger(logger_name, formatter, sinks, level), _safe_type(safe_type), _async_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::consumerThreadFunction, this, std::placeholders::_1), safe_type)) // 需要加上&AsyncLogger::，否则会报错
        {}
        void logIt(const std::string &message)
        {
            _async_looper->push(message);
        }

    public:
        // 由异步线程进行调用，即回调函数，完成消费，即日志的实际落地工作
        void consumerThreadFunction(Buffer &buffer)
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(buffer.begin(), buffer.readableSize());
                // buffer.pop(buffer.readableSize());
            }
        }
        void modifyAsyncLoggerAndLooperSafeType(AsyncLooperSafeType safe_type)      // 修改任务处理器的安全类型
        {
            _safe_type = safe_type;
            _async_looper->modifyLooperSafeType(safe_type);
        }

    private:
        AsyncLooperSafeType _safe_type;     // 任务处理器的安全类型
        AsyncLooper::ptr _async_looper;     //  任务处理器对象
    };

    // 局部建造者，建造的对象的局部的，而不是全局的
    class LocalLoggerBuilder : public Builder
    {
    public:
        using ptr = std::shared_ptr<LocalLoggerBuilder>;
        // LocalLoggerBuilder() = default;
        Logger::ptr build()
        {
            if (_logger_name.empty())       // 日志器需要有名称标识
            {
                std::cerr << "LocalLoggerBuilder, _logger_name is empty" << std::endl;
                // return nullptr;
                // 直接出错,退出
                abort();
            }
            if (_formatter.get() == nullptr)        // 格式
            {
                std::cout << "LocalLoggerBuilder _formatter not set, set default" << std::endl;
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                std::cout << "LocalLoggerBuilder _sinks not set, set default, StdOutSink" << std::endl;
                _sinks.push_back(SinkFactory::createSink<StdOutSink>());
            }
            if (_logger_type == Logger::LoggerType::ASYNC_LOGGER)
                return std::make_shared<AsyncLogger>(_logger_name, _formatter, _sinks, _level /*, _safe_type*/);
            else
                return std::make_shared<SyncLogger>(_logger_name, _formatter, _sinks, _level);

            // return std::shared_ptr<Logger>(nullptr);            // 不能使用make_shared，要直接创建shared_ptr
        }
    };

    // 日志器管理类
    // 单例模式 -->突破创建日志器之后，受到日志器作用域的访问属性限制，即访问区域的限制
    // 懒汉模式的单例
    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()     // 获取单例对象
        {
            static LoggerManager _eton;        // c++11之后安全，只创建一次
            return _eton;
        }
        bool loggerIsExists(const std::string &logger_name)     // 判断日志器是否存在
        {
            // 加锁，安全
            std::unique_lock<std::mutex> ul(_mutex);
            return _loggers.find(logger_name) != _loggers.end();
        }
        Logger::ptr getLogger(const std::string &logger_name)       // 获取对应的日志器
        {
            // 加锁，安全
            std::unique_lock<std::mutex> ul(_mutex);
            auto it = _loggers.find(logger_name);
            if (it == _loggers.end())
                return Logger::ptr();
            return it->second;
        }
        // 压入日志器
        void pushLogger(const Logger::ptr &logger) // 不会修改，可加const修饰
        {
            // 判断一下，防止重复压入，即将已存在于_loggers集合中的日志器被覆盖
            if(loggerIsExists(logger->getLoggerName()))
            {
                std::cout << "LoggerManager, pushLogger operator fail, reason: the name of logger is exists" << std::endl;
                return;     // 错误问题不大，只是退出函数即可，没必要出错结束程序
            }
            // 加锁，安全
            std::unique_lock<std::mutex> ul(_mutex);
            _loggers.insert(std::make_pair(logger->getLoggerName(), logger));
        }
        // 弹出日志器，与上方的压入操作对应，完善些
        void popLogger(const std::string &logger_name)
        {
            if(!loggerIsExists(logger_name))
            {
                std::cout << "LoggerManager, popLogger operator fail, reason: the name of logger is non exists" << std::endl;
                return;     // 错误问题不大，只是退出函数即可，没必要出错结束程序
            }
            std::unique_lock<std::mutex> ul(_mutex);
            _loggers.erase(logger_name);
        }
        Logger::ptr getDefaultLogger()          // 获取默认日志器
        {
            // 加锁，安全
            std::unique_lock<std::mutex> ul(_mutex);
            return _root_logger;
        }

    private:
        LoggerManager()
        {
            // snowdragon::LocalLoggerBuilder llb;
            std::unique_ptr<LocalLoggerBuilder> llb(new LocalLoggerBuilder());
            // 默认日志器的创建
            llb->buildLoggerName("root");
            // 下面那条语句可加可不加，不加，没有会自动push一个StdOutSink
            llb->buildLoggerSink<StdOutSink>();
            llb->buildLoggerType(Logger::LoggerType::SYNC_LOGGER);
            _root_logger = llb->build();
            _loggers.insert(std::make_pair("root", _root_logger));
        }
        // 单例，全都禁掉
        LoggerManager(const LoggerManager &) = delete;
        LoggerManager &operator=(const LoggerManager &) = delete;

    private:
        Logger::ptr _root_logger;               // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers;      // 存在日志器
        std::mutex _mutex;              // 用锁，线程安全
    };
    // 全局日志器建造者类，实现在一个日志器创建完毕后，直接添加到单例的日志器管理器（LoggerManager）中，
    // 在任何位置，通过日志器名称就能获取到指定的日志器进行日志的输出操作
    class GlobalLoggerBuilder : public Builder
    {
    public:
        using ptr = std::shared_ptr<GlobalLoggerBuilder>;
        Logger::ptr build()
        {
            if (_logger_name.empty())
            {
                std::cerr << "LocalLoggerBuilder _logger_name is empty or not set" << std::endl;
                // return nullptr;
                // 直接出错,退出
                abort();
            }
            // 日志器得不存在，否则无意义。因为这是在生成日志器
            assert(!LoggerManager::getInstance().loggerIsExists(_logger_name));
            if (_formatter.get() == nullptr)
            {
                std::cout << "LocalLoggerBuilder _formatter not set, set default" << std::endl;
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                std::cout << "LocalLoggerBuilder _sinks not set, set default, StdOutSink" << std::endl;
                _sinks.push_back(SinkFactory::createSink<StdOutSink>());
            }
            Logger::ptr ret;
            if (_logger_type == Logger::LoggerType::ASYNC_LOGGER)
                ret = std::make_shared<AsyncLogger>(_logger_name, _formatter, _sinks, _level /*, _safe_type*/);
            else
                ret = std::make_shared<SyncLogger>(_logger_name, _formatter, _sinks, _level);
            // 记得将生成的日志器加入管理者中
            LoggerManager::getInstance().pushLogger(ret);
            return ret;
        }
    };
}

#endif